package com.lzj.admin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.lzj.admin.dto.TreeDto;
import com.lzj.admin.mapper.GoodsMapper;
import com.lzj.admin.model.RespDataBean;
import com.lzj.admin.pojo.Goods;
import com.lzj.admin.pojo.GoodsType;
import com.lzj.admin.mapper.GoodsTypeMapper;
import com.lzj.admin.service.IGoodsTypeService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lzj.admin.utils.AssertUtil;
import com.lzj.admin.utils.PinYinUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import com.lzj.admin.utils.PinYinUtil;

/**
 * <p>
 * 商品类别表 服务实现类
 * </p>
 *
 * @author luoyoumou
 * @date 2022-12-05
 */
@Service
public class GoodsTypeServiceImpl extends ServiceImpl<GoodsTypeMapper, GoodsType> implements IGoodsTypeService {

    @Resource
    GoodsMapper goodsMapper;

    @Resource
    GoodsTypeMapper goodsTypeMapper;

    /**
     * 查询所有类别
     * @param typeId
     * @return
     */
    @Override
    public List<TreeDto> queryAllGoodsTypes(Integer typeId) {
        List<TreeDto> treeDtos = this.baseMapper.queryAllGoodsTypes();
        if(null != typeId){
            for (TreeDto treeDto : treeDtos) {
                if(treeDto.getId().equals(typeId)){
                    // 设置节点选中
                    treeDto.setChecked(true);
                    break;
                }
            }
        }
        return treeDtos;
    }

    /**
     * 查询所有子类型id集合根据当前点击的类型id
     * @param typeId
     * @return
     */
    @Override
    public List<Integer> queryAllSubTypeIdsByTypeId(Integer typeId) {
        GoodsType goodsType = this.getById(typeId);
        if(goodsType.getpId()==-1 ) {
            // 所有类别
            return this.list().stream().map(GoodsType::getId).collect(Collectors.toList());
        }
        List<Integer> result = new ArrayList<Integer>();
        result.add(typeId);
        return getSubTypeIds(typeId,result);
    }

    /**
     * 查询所有子类型id集合根据商品类别名称 模糊递归匹配 返回所有级联 类别Id 数据集
     * @param typeName
     * @return
     */
    @Override
    public List<Integer> queryAllSubTypeIdsByTypeId(String typeName) {
        QueryWrapper<GoodsType> goodsTypeQueryWrapper = new QueryWrapper<GoodsType>().like("name",typeName).or().like("fpy_name",typeName);
        List<GoodsType> tGoodsType = goodsTypeMapper.selectList(goodsTypeQueryWrapper);

        if(tGoodsType.isEmpty()){
            // 如果没有满足条件的数据，就返回一个不存在的类别ID，使其页面查询为空
            return Collections.singletonList(-2);
        } else {
            List<Integer> result = new ArrayList<Integer>();
            for (GoodsType goodsType : tGoodsType){
                Integer typeId = goodsType.getId();
                result.addAll(queryAllSubTypeIdsByTypeId(typeId));
            }
            return result;
        }
    }

    public String queryParentTypeNameByTypeId(Integer typeId){
        GoodsType goodsType = this.getById(typeId);
        QueryWrapper<GoodsType> goodsTypeQueryWrapper = new QueryWrapper<GoodsType>().eq("id",goodsType.getpId());
        GoodsType tGoodsType =  goodsTypeMapper.selectOne(goodsTypeQueryWrapper);
        if(tGoodsType.getName().isEmpty()){
            return null;
        } else {
            return tGoodsType.getName();
        }
    }

    /**
     * 商品类型列表
     * @return
     */
    @Override
    public RespDataBean<GoodsType> goodsTypeList() {
        List<GoodsType> list = this.list();
        return new RespDataBean<GoodsType>(0,"查询成功",list);
    }

    /**
     * 添加商品类别
     * 1. 商品类别名称 非空
     * 2. 商品类别上级id 非空
     * 3. 考虑父类别 ( 如果 父类别本身 state = 0 )
     *      设置父类别 state = 1
     * 4. 相同类别下：类别名不能重复
     * @param goodsType
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void saveGoodsType(GoodsType goodsType) {
        AssertUtil.isTrue(StringUtils.isBlank(goodsType.getName()),"商品类别名称不能为空！");
        AssertUtil.isTrue(null == goodsType.getpId(),"请指定父类别！");
        AssertUtil.isTrue(null != findGoodsTypeNameByPid(goodsType.getpId(),goodsType.getName().trim()),"相同类别下，类别名不能重名！");
        goodsType.setName(goodsType.getName().trim());
        goodsType.setState(0);
        goodsType.setIcon("icon-folder");
        goodsType.setFpyName(PinYinUtil.getFirstSpell(goodsType.getName().trim()));
        AssertUtil.isTrue(!this.save(goodsType),"记录添加失败！");
        GoodsType parent = this.getById(goodsType.getpId());
        if(parent.getState()==0) {
            parent.setState(1);
        }
        AssertUtil.isTrue(!(this.updateById(parent)),"商品类别记录添加失败！");
    }

    /**
     * 更新商品类别
     * 1. 商品类别名称 非空
     * 2. 相同类别下：类别名不能重复
     * @param goodsType
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void updateGoodsType(GoodsType goodsType) {
        AssertUtil.isTrue(StringUtils.isBlank(goodsType.getName().trim()),"商品类别名称不能为空！");
        AssertUtil.isTrue(null != findGoodsTypeNameById(goodsType.getId(),goodsType.getName()),"相同类别下，类别名不能重名！");
        goodsType.setName(goodsType.getName().trim());
        goodsType.setFpyName(PinYinUtil.getFirstSpell(goodsType.getName().trim()));
        AssertUtil.isTrue(!(this.updateById(goodsType)),"商品类别记录更新失败！");
    }

    /**
     * 指定类别id，检查同级别下（兄弟节点）是否存在同名兄弟类别节点
     * @param id
     * @param name
     * @return
     */
    private GoodsType findGoodsTypeNameById(Integer id, String name) {
        GoodsType goodsType = this.getById(id);
        return this.baseMapper.selectOne(new QueryWrapper<GoodsType>().notIn("id",id).eq("p_id",goodsType.getpId()).eq("name",name).last("limit 1"));
    }

    /**
     * 功能：指定 p_id，检查是否存在同名子类别节点
     * @param pId
     * @param name
     * @return
     */
    private GoodsType findGoodsTypeNameByPid(Integer pId, String name) {
        return this.baseMapper.selectOne(new QueryWrapper<GoodsType>().eq("p_id",pId).eq("name",name).last("limit 1"));
    }

    /**
     * 功能：指定 p_id，检查是否存在相关子类别节点
     * @param pId
     * @return
     */
    private GoodsType findGoodsTypeNameByPid(Integer pId) {
        return this.baseMapper.selectOne(new QueryWrapper<GoodsType>().eq("p_id",pId).last("limit 1"));
    }

    /**
     * 商品类别-删除
     * 1. 删除记录必须存在
     * 2. 如果类别下存在子类别 不允许删除
     * 3. 该类别下存在商品 不允许删除
     * 4. 如果节点删除后 上级节点没有子节点 此时设置上级节点 state=0
     * @param id
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    public void deleteGoodsType(Integer id) {
        GoodsType tempGoodsType = this.getById(id);
        AssertUtil.isTrue(null == tempGoodsType,"待删除的记录不存在！");
        AssertUtil.isTrue(null != findGoodsTypeNameByPid(id),"存在子类别，暂不支持级联删除！");

        QueryWrapper<Goods> goodsQueryWrapper = new QueryWrapper<Goods>().eq("type_id",id).last("limit 1");
        List<Goods> tempGoods = goodsMapper.selectList(goodsQueryWrapper);
        AssertUtil.isTrue(CollectionUtils.isNotEmpty(tempGoods),"该类别下已有商品，不允许被删除！");

        // 只要存在两条记录，就说明：删除该节点后，其父节点还有相关子节点
        QueryWrapper<GoodsType> goodsTypeQueryWrapper = new QueryWrapper<GoodsType>().eq("p_id",tempGoodsType.getpId()).last("limit 2");
        List<GoodsType> tGoodsType = goodsTypeMapper.selectList(goodsTypeQueryWrapper);

        if(tGoodsType.size()==1){
            AssertUtil.isTrue(!(this.update(new UpdateWrapper<GoodsType>().set("state",0).eq("id",tempGoodsType.getpId()))),"类别删除失败！");
        }
        AssertUtil.isTrue(!(this.removeById(id)),"商品类别记录删除失败！");
    }

    private List<Integer> getSubTypeIds(Integer typeId, List<Integer> result) {
        List<GoodsType> goodsTypes = this.baseMapper.selectList(new QueryWrapper<GoodsType>().eq("p_id",typeId));
        if(CollectionUtils.isNotEmpty(goodsTypes)){
            goodsTypes.forEach(gt->{
                result.add(gt.getId());
                getSubTypeIds(gt.getId(),result);
            });
        }
        return result;
    }
}
